use std::fmt::Debug;

use futures_util::future::BoxFuture;
use sqlx::{Database, Pool, Transaction};
use tracing::error;

pub fn transaction<'a, F, R, E, DB>(pool: &'a Pool<DB>, callback: F) -> BoxFuture<'a, Result<R, E>>
where
    for<'c> F:
        FnOnce(&'c mut Transaction<'_, DB>) -> BoxFuture<'c, Result<R, E>> + 'a + Send + Sync,
    // Self: Sized,
    R: Send,
    E: From<sqlx_core::Error> + Send + Debug,
    DB: Database
{
    Box::pin(async move {
        let mut transaction = pool.begin().await?; //.map_err(|err| Status::map_error(err))?;

        let ret = callback(&mut transaction).await;

        match ret {
            Ok(ret) => {
                transaction.commit().await?;
                // .map_err(|err| Status::map_error(err))?;

                Ok(ret)
            }
            Err(err) => {
                // DataBaseError::a();
                transaction.rollback().await?;
                // .map_err(|err| Status::map_error(err))?;
                // err.into()
                // match err {
                //     Error::Io(err) => {
                //     }
                // }
                error!("db error: {:?}", err); // ::from(err));
                Err(err)
            }
        }
    })
}
